package com.itita.ww2.game.user;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Seconds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.itita.ww2.redis.RedisUtil;
import com.itita.ww2.redis.cache.Table;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSObject;
import com.itita.ww2.data.GameConfig;
import com.itita.ww2.model.CodeType;
import com.itita.ww2.model.user.DevTime;
import com.itita.ww2.model.user.DevTime.DevTimeType;
import com.itita.ww2.model.user.UserProfile;
import com.itita.ww2.utils.TimeUtil;

/**
 * 时间管理器
 * @author NorthLan
 *
 */
public class UserDevTimeManager {
	private static final Logger logger = LoggerFactory.getLogger(UserDevTimeManager.class);
	private int uid;
	private UserProfile userProfile;
	private Map<String, DevTime> devTimeMap;

	public UserDevTimeManager(UserProfile userProfile) {
		this.userProfile = userProfile;
		this.uid = userProfile.getUid();
		devTimeMap = new HashMap<>();
	}

	/**
	 * 添加新的时间
	 */
	public void addDevTime(DevTimeType type, String code, int duration) {
		DevTime dt = new DevTime(type, code, TimeUtil.getUtcNow().getMillis(), duration,
				TimeUtil.getUtcNow().plusSeconds(duration).getMillis());
		this.devTimeMap.put(dt.getKey(), dt);
	}

	//	/**
	//	 * 添加新的时间计划(读表)
	//	 */
	//	public void addDevTime(DevTimeType type, String code, int level) {
	//		String newCode = code + "_" + level;
	//		ISFSObject unitObj = GameConfig.getGameConfig("BuildingLevelLimit").getSFSObject(newCode);
	//		final int duration = (int) DataUtil.nullValueHandler(unitObj.getInt("Time"), 0);
	//		this.addDevTime(type, newCode, duration, 1);
	//	}

	/**
	 * 添加新的资源时间计划
	 */
	public void addResDevTime(String code) {
		// 判断用户有没有其他资源正在更新,如果有,将新资源的时间设置为之前的某一个
		long endTime = TimeUtil.getUtcNowMillis();
		for (String key : devTimeMap.keySet()) {
			if (key.contains(DevTimeType.RESOURCE.toString())) {
				endTime = devTimeMap.get(key).getEndTime();
				break;
			}
		}
		devTimeMap.put(DevTime.genericKey(DevTimeType.RESOURCE, code),
				new DevTime(DevTimeType.RESOURCE, code, 0, 0, endTime));
	}

	/**
	 * 新增疲劳回复时间计划
	 */
	public void addFatigueDevTime() {
		devTimeMap.put(DevTime.genericKey(DevTimeType.FATIGUE, ""),
				new DevTime(DevTimeType.FATIGUE, "", 0, 0, TimeUtil.getUtcNowMillis()));
	}

	/**
	 * 移除时间
	 */
	public void removeDevTime(DevTimeType type, String code) {
		this.devTimeMap.remove(DevTime.genericKey(type, code));
	}

	/**
	 * 获取某项时间计划
	 */
	public DevTime getDevTime(DevTimeType type, String code) {
		return this.devTimeMap.get(DevTime.genericKey(type, code));
	}

	/**
	 * 更新结束时间
	 */
	public long updateDevTime(DevTimeType type, String code, long endTime) {
		String key = DevTime.genericKey(type, code);
		if (!this.devTimeMap.containsKey(key)) {
			return 0; // 计划不存在
		}
		DevTime dt = this.devTimeMap.get(key);
		long ret = dt.getEndTime();
		dt.updateEndTime(endTime);
		this.update();
		return ret;
	}

	/**
	 * 是否在时间计划当中
	 */
	public boolean isDevTimeExists(DevTimeType type, String code) {
		return this.devTimeMap.containsKey(DevTime.genericKey(type, code));
	}

	/**
	 * 是否时间到
	 */
	public boolean isTimeup(DevTimeType type, String code) {
		if (!isDevTimeExists(type, code)) { // 没有升级时间
			return false;
		}
		DevTime dt = devTimeMap.get(DevTime.genericKey(type, code));
		return TimeUtil.getUtcNowMillis() >= dt.getEndTime();
	}

	/**
	 * 计算  时间<->金条数
	 */
	public int calculateTimeGold(DevTimeType type, String code) {
		DevTime dt = this.devTimeMap.get(DevTime.genericKey(type, code));
		DateTime endTime = new DateTime(dt.getEndTime());
		long seconds = Seconds.secondsBetween(TimeUtil.getUtcNow(), endTime).getSeconds();
		if (seconds == 0) {
			return 0;
		}
		int price = 0;
		CodeType codeType = CodeType.codeValueOf(code);
		switch (codeType) {
		case ARMY:
			price = Math.round(GameConfig.getTimeGoldRatioArmy() * seconds);
			break;
		case BUILDING:
			price = Math.round(GameConfig.getTimeGoldRatioBD() * seconds);
			break;
		default:
			logger.warn("Not supported type: {}", codeType.toString());
			break;
		}
		if (price < 1) {
			price = 1;
		}
		return price;
	}

	public synchronized void load() {
		Table t = UserService.getInstance().getCacheUserDataTable();
		ISFSObject devTimeObj = SFSObject.newFromJsonData(t.getValue(RedisUtil.genericKey(this.uid), "devTime"));
		devTimeMap.clear();
		for (String key : devTimeObj.getKeys()) {
			DevTime dt = DevTime.newFromJsonData(key, devTimeObj.getSFSObject(key));
			devTimeMap.put(key, dt);
		}
	}

	public synchronized void update() {
		Table t = UserService.getInstance().getCacheUserDataTable();
		t.setValue(RedisUtil.genericKey(this.uid), "devTime", toSFSObject().toJson());
	}

	public ISFSObject toSFSObject() {
		ISFSObject ret = SFSObject.newInstance();
		for (DevTime dt : devTimeMap.values()) {
			ret.putSFSObject(dt.getKey(), dt.toSFSObject());
		}
		return ret;
	}

	private boolean isInit() {
		com.itita.ww2.redis.cache.Table t = UserService.getInstance().getCacheUserDataTable();
		String data = t.getValue(RedisUtil.genericKey(userProfile.getUid()), "devTime");
		return StringUtils.isNotBlank(data) && !data.equals("null");
	}

	public void initialize() {
		if (!isInit()) {
			this.update();
		} else {
			load();
		}
	}

	public UserProfile getUserProfile() {
		return this.userProfile;
	}
}
